﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Tao.OpenGl;

namespace AvantGameMachine.Graphics
{
    public delegate void PositionChangedDelegate();
    public delegate void ScaleChangedDelegate();
    public delegate void RotationChangedDelegate();

    public class Transformable
    {
        protected PosVector position = new PosVector();
        protected PosVector scale = new PosVector(1.0f, 1.0f, 1.0f);
        protected PosVector rotation = new PosVector();
        private PosVector oldposition;
        private PosVector oldscale;
        private PosVector oldrotation;
        protected PositionChangedDelegate pChanged = null;
        protected ScaleChangedDelegate sChanged = null;
        protected RotationChangedDelegate rChanged = null;
        protected Matrix localTransformation = Matrix.Identity(4);
        protected Matrix globalTransformation = Matrix.Identity(4);
        protected bool transformationChanged = true;

        public const int TRANS_POSITION = 0;
        public const int TRANS_ROTATION = 1;
        public const int TRANS_SCALE = 2;
        public const int TRANS_LAST = 2;

        public Transformable()
        {
            oldposition = position;
            oldscale = scale;
            oldrotation = rotation;
        }

        public void SetTransformableProperty(int _prop,PosVector _propValue)
        {
            switch (_prop)
            {
                case TRANS_POSITION:
                    Position = _propValue;
                    break;

                case TRANS_ROTATION:
                    Rotation = _propValue;
                    break;

                case TRANS_SCALE:
                    Scale = _propValue;
                    break;
            }
        }

        public virtual PosVector Position
        {
            get { return position; }
            set
            {
                if (position.X != value.X || position.Y != value.Y || position.Z != value.Z)
                {
                    oldposition = position;
                    position = value;
                    TransformationChanged = true;
                    if (pChanged != null)
                    {
                        pChanged();
                    }
                }

            }
        }

        public float PositionX
        {
            get { return position.X;  }
            set
            {
                if (position.X != value)
                {
                    oldposition.X = position.X;
                    position.X = value;
                    TransformationChanged = true;
                    if (pChanged != null)
                    {
                        pChanged();
                    }
                }

            }
        }

        public float PositionY
        {
            get { return position.Y;  }
            set
            {
                if (position.Y != value)
                {
                    oldposition.Y = position.Y;
                    position.Y = value;
                    TransformationChanged = true;
                    if (pChanged != null)
                    {
                        pChanged();
                    }
                }
            }
        }

        public float PositionZ
        {
            get { return position.Z;  }
            set
            {
                if (position.Z != value)
                {
                    oldposition.Z = position.Z;
                    position.Z = value;
                    TransformationChanged = true;
                    if (pChanged != null)
                    {
                        pChanged();
                    }
                }
            }
        }

        public virtual PosVector Scale
        {
            get { return scale; }
            set
            {
                if (scale.X != value.X || scale.Y != value.Y || scale.Z != value.Z)
                {
                    oldscale = scale;
                    scale = value;
                    TransformationChanged = true;
                    if (sChanged != null)
                    {
                        sChanged();
                    }
                }
            }
        }

        public float ScaleX
        {
            get { return scale.X;  }
            set
            {
                if (scale.X != value)
                {
                    oldscale.X = scale.X;
                    scale.X = value;
                    TransformationChanged = true;
                    if (sChanged != null)
                    {
                        sChanged();
                    }
                }
            }
        }

        public float ScaleY
        {
            get { return scale.Y;  }
            set
            {
                if (scale.Y != value)
                {
                    oldscale.Y = scale.Y;
                    scale.Y = value;
                    TransformationChanged = true;
                    if (sChanged != null)
                    {
                        sChanged();
                    }
                }
            }
        }

        public float ScaleZ
        {
            get { return scale.Z;  }
            set
            {
                if (scale.Z != value)
                {
                    oldscale.Z = scale.Z;
                    scale.Z = value;
                    TransformationChanged = true;
                    if (sChanged != null)
                    {
                        sChanged();
                    }
                }
            }
        }

        public virtual PosVector Rotation
        {
            get { return rotation;  }
            set
            {
                if (rotation.X != value.X || rotation.Y != value.Y || rotation.Z != value.Z)
                {
                    oldrotation = rotation;
                    rotation = value;
                    TransformationChanged = true;
                    if (rChanged != null)
                    {
                        rChanged();
                    }
                }
            }
        }

        public float RotationX
        {
            get { return rotation.X;  }
            set
            {
                if (rotation.X != value)
                {
                    oldrotation.X = rotation.X;
                    rotation.X = value;
                    TransformationChanged = true;
                    if (rChanged != null)
                    {
                        rChanged();
                    }
                }
            }
        }

        public float RotationY
        {
            get { return rotation.Y;  }
            set
            {
                if (rotation.Y != value)
                {
                    oldrotation.Y = rotation.Y;
                    rotation.Y = value;
                    TransformationChanged = true;
                    if (rChanged != null)
                    {
                        rChanged();
                    }
                }
            }
        }

        public float RotationZ
        {
            get { return rotation.Z;  }
            set
            {
                if (rotation.Z != value)
                {
                    oldrotation.Z = rotation.Z;
                    rotation.Z = value;
                    TransformationChanged = true;
                    if (rChanged != null)
                    {
                        rChanged();
                    }
                }
            }
        }

        protected bool TransformationChanged
        {
            get { return transformationChanged; }
            set { transformationChanged = value; }
        }

        public static double ToDegrees(double _radians)
        {
            return (_radians / Math.PI) * 180.0;
        }

        public static double ToRadians(double _degrees)
        {
            return (_degrees / 180.0) * Math.PI;
        }

        public static float ToDegreesf(double _radians)
        {
            return (float)((_radians / Math.PI) * 180.0);
        }

        public static float ToRadiansf(double _degrees)
        {
            return (float)((_degrees / 180.0) * Math.PI);
        }

        public virtual void PreRender()
        {
            Gl.glPushMatrix();
//            if (transformationChanged)
  //          {
            if (rotation.X != 0.0f)
                Gl.glRotatef(rotation.X, 1.0f, 0.0f, 0.0f);            // Rotate on x

            if (rotation.Y != 0.0f)
                Gl.glRotatef(rotation.Y, 0.0f, 1.0f, 0.0f);            // Rotate on y

            if (rotation.Z != 0.0f)
                Gl.glRotatef(rotation.Z, 0.0f, 0.0f, 1.0f);            // Rotate on z

            if (position.X != 0.0f || position.Y != 0.0f || position.Z != 0.0f)
                Gl.glTranslatef(position.X, position.Y, position.Z);

            if (scale.X != 1.00f || scale.Y != 1.00f || scale.Z != 1.00f)
                Gl.glScalef(scale.X, scale.Y, scale.Z);
    //        }
      //      else
        //    {
          //  }
        }

        public virtual void PostRender()
        {
            Gl.glPopMatrix();
        }

        public override string ToString()
        {
            return "P:" + position.ToString() + " R:" + rotation.ToString() + " S:" + scale.ToString();
        }

    }
}
